如同前一天所說的,Rive 本身的語法都不難,但很多設計模式上的問題,要實務上有遇過才會有一些想法,例如今天要講的是,關於程式碼怎麼拆分的部分。以下會用 Vue 3 當範例,不過因為 composable 跟 hook 有 87% 像,所以概念上應該都是相通的。
我們應該都知道(吧),程式碼要盡量拆分,無論是 funciton 還是檔案的行數,都要盡量越短越好。所以假設有兩個 Rive,這樣寫其實不太好,因為檔案太長了。
// Bad.
// Main.vue
<template>
<canvas id="partA">
<canvas id="partB">
</template>
<script setup lang="ts">
const initPartARive = function() {...}
const initPartBRive = function() {...}
const stateForPartA = 'someState'
const stateForPartA2 = 'someState2'
const stateForPartB = 'someState'
const stateForPartB2 = 'someState2'
const stateForPartB3 = 'someState3'
const partABussinessLogic = function() {...}
const partABussinessLogic2 = function() {...}
const partARiveLogic = function() {...}
const partARiveLogic2 = function() {...}
const partARiveLogic3 = function() {...}
const partBBussinessLogic = function() {...}
const partBRiveLogic = function() {...}
const partBRiveLogic2 = function() {...}
onMounted(() => {
partABussinessLogic2()
partARiveLogic()
partBRiveLogic2()
})
</script>
通常狀態跟邏輯只會越來越多,光是兩個 Rive 就這麼長了,以後只會越來越長。雖然聽起來有點好笑,但實務上就我們的經驗,檔案長度真的還蠻容易爆走的,太長的檔案非常影響可讀性跟可維護性,檔案長度應該盡量維持在 100 行以內。我個人在 code review 的時候,只要是我一眼看不完的檔案,我都會覺得太長,plain view doctrine。超過 200 行的檔案,我都覺得是世界奇觀。
既然太長了,那最直覺的方法應該是把 partA & partB 拆開,通常會拆成這樣。
// Good.
// Main.vue
<template>
<canvas id="partA">
<canvas id="partB">
</template>
<script setup lang="ts">
import usePartA from './usePartA.ts'
import usePartB from './usePartB.ts'
usePartA()
usePartB()
</script>
// usePartA.ts
export defualt () => {
// All things abut partA.
}
// usePartB.ts
export defualt () => {
// All things abut partB.
}
這樣拆其實就不錯了,把 partA & partB 拆開有效的降低耦合提高內聚,但此時 usePartA.ts 會變成這樣,其實還是有點長。
為了更進一步解耦,可以把商業邏輯跟 Rive 邏輯拆開,大概會變成這樣。
// Better.
// Main.vue
<template>
<canvas id="partA">
<canvas id="partB">
</template>
<script setup lang="ts">
import usePartA from './usePartA.ts'
import usePartB from './usePartB.ts'
usePartA()
usePartB()
</script>
// usePartA.ts
import usePartABusinessLogic from './usePartABusinessLogic.ts'
import usePartARiveLogic from './usePartARiveLogic.ts'
export default () => {
const { riveLogic1, riveLogic2 } = usePartARiveLogic()
partABusinessLogic({ riveLogic1, riveLogic2 }) // Dependencies injection.
}
通常拆到這樣子以後,檔案的行數應該就夠短了,如果有搭配 auto import 之類的插件的話,可以在更進一步縮短程式碼,最終會變成下圖這樣,行數縮短將近 50%。
這種縮短程式碼的方式根本稱不上技巧,比較多是心態與習慣的問題,但他真的會有效的改善程式碼的可讀性跟可維護性。雖然不是說拆檔案一定就會比較好讀,但不拆開落落長一串絕對不好讀,沒有人喜歡看長文,就好像為什麼鐵人賽要拆成 30 天一樣。
不過的確,除了要盡量把程式碼拆開以外,到底要怎麼拆也是一個問題,把商業邏輯跟 Rive 邏輯拆開是一個面向,那商業邏輯跟商業邏輯內部之間,或是 Rive 邏輯跟 Rive 邏輯內部之間又要怎麼拆?這就是物件 / 事件 / 函式導向的問題,我們明天會再提到。